﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace HappyTemplate.BuiltInFunctions
{
	public abstract class BuiltInFunctionBase
	{
		readonly string _name;
		readonly int _maxArgCount = -1;
		readonly int _minArgCount = -1;
		readonly bool _forceNonNullAllArguments = true;

		 
		public string Name { get { return _name; } }
		public int MaxArgCount { get { return _maxArgCount;  } }
		public int MinArgCount { get { return _minArgCount; } }

		public bool ForceNonNullAllArguments
		{
			get { return _forceNonNullAllArguments; }
		}

		protected BuiltInFunctionBase(string name, int argCount)
		{
			_name = name;
			_minArgCount = argCount;
			_maxArgCount = argCount;
		}

		protected BuiltInFunctionBase(string name, int minArgCount, int maxArgCount)
		{
			_name = name;
			_maxArgCount = maxArgCount;
			_minArgCount = minArgCount;
		}

		protected BuiltInFunctionBase(string name, int argCount, bool forceNonNullAllArguments)
		{
			_name = name;
			_minArgCount = argCount;
			_maxArgCount = argCount;
			_forceNonNullAllArguments = forceNonNullAllArguments;
		}

		protected BuiltInFunctionBase(string name, int minArgCount, int maxArgCount, bool forceNonNullAllArguments)
		{
			_name = name;
			_maxArgCount = maxArgCount;
			_minArgCount = minArgCount;
			_forceNonNullAllArguments = forceNonNullAllArguments;
		}

		public abstract object Invoke(ArgumentCollection arguments);

		public static Dictionary<string, BuiltInFunctionBase> DiscoverBuiltinFunctions(Assembly assembly)
		{
			Dictionary<string, BuiltInFunctionBase> retval = new Dictionary<string, BuiltInFunctionBase>();
			foreach(Type t in assembly.GetTypes())
				try { 
					if(!t.IsAbstract && typeof(BuiltInFunctionBase).IsAssignableFrom(t))
					{
						BuiltInFunctionBase f = (BuiltInFunctionBase)Activator.CreateInstance(t);
						if(retval.ContainsKey(f.Name))
							throw new BuiltInFunctionException(
								Resources.MiscMessages.DuplicateBuiltInFunctionName_Name, 
								f.Name);

						retval.Add(f.Name, f);
					}
				} catch(Exception e)
				{
					throw new BuiltInFunctionException(e, Resources.MiscMessages.CouldNotInstantiateBuiltinFunction_Name, t.FullName);
				}

			return retval;
		}
	}


}